package org.tloss.web.editor.utils;

import java.util.ArrayList;
import java.util.List;

import org.eclipse.core.resources.IResourceChangeListener;
import org.eclipse.jface.layout.TreeColumnLayout;
import org.eclipse.jface.viewers.CellEditor;
import org.eclipse.jface.viewers.CheckboxTreeViewer;
import org.eclipse.jface.viewers.ColumnLabelProvider;
import org.eclipse.jface.viewers.ColumnWeightData;
import org.eclipse.jface.viewers.ComboBoxCellEditor;
import org.eclipse.jface.viewers.EditingSupport;
import org.eclipse.jface.viewers.ICheckStateProvider;
import org.eclipse.jface.viewers.TreeViewer;
import org.eclipse.jface.viewers.TreeViewerColumn;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.MouseEvent;
import org.eclipse.swt.events.MouseListener;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.layout.RowLayout;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Tree;
import org.eclipse.swt.widgets.TreeColumn;
import org.tloss.web.editor.model.LogicalProvider;
import org.tloss.web.editor.model.oper.Displayable;
import org.tloss.web.editor.model.oper.logical.AndOperator;
import org.tloss.web.editor.model.oper.logical.CompareLogical;
import org.tloss.web.editor.model.oper.logical.CompareOperator;
import org.tloss.web.editor.model.oper.logical.ComplexLogical;
import org.tloss.web.editor.model.oper.logical.EqualOperator;
import org.tloss.web.editor.model.oper.logical.GreatethanOperator;
import org.tloss.web.editor.model.oper.logical.GreatethanOrEqual;
import org.tloss.web.editor.model.oper.logical.IsNotNullOperator;
import org.tloss.web.editor.model.oper.logical.IsNullOperator;
import org.tloss.web.editor.model.oper.logical.LessthanOperator;
import org.tloss.web.editor.model.oper.logical.LessthanOrEqualOperator;
import org.tloss.web.editor.model.oper.logical.LikeOperator;
import org.tloss.web.editor.model.oper.logical.Logical;
import org.tloss.web.editor.model.oper.logical.NotEqualOperator;
import org.tloss.web.editor.model.oper.logical.NotOperator;
import org.tloss.web.editor.model.oper.logical.OrOperator;
import org.tloss.web.editor.model.oper.math.MathOperand;
import org.tloss.web.editor.sql.editors.LogicalListContentProvider;

public abstract class LogicalBuilder {
	private AndOperator andOperator = new AndOperator();
	private OrOperator orOperator = new OrOperator();
	private NotOperator notOperator = new NotOperator();
	protected CheckboxTreeViewer treeViewer;
	protected IResourceChangeListener dirtyListener;
	protected LogicalProvider provider = null;

	public abstract List<Object> getOperandList();

	public List<CompareOperator> getCompareOperators(){
		List<CompareOperator> compareOperators = new ArrayList<CompareOperator>();
		compareOperators.add(null);
		compareOperators.add(new EqualOperator());
		compareOperators.add(new GreatethanOperator());
		compareOperators.add(new GreatethanOrEqual());
		compareOperators.add(new LessthanOperator());
		compareOperators.add(new LessthanOrEqualOperator());
		compareOperators.add(new NotEqualOperator());
		compareOperators.add(new IsNotNullOperator());
		compareOperators.add(new IsNullOperator());
		compareOperators.add(new LikeOperator());
		return compareOperators;
	}
	public void setDirtyListener(IResourceChangeListener dirtyListener) {
		this.dirtyListener = dirtyListener;
	}

	public void setLogicalProvider(LogicalProvider provider) {
		this.provider = provider;
		if (treeViewer != null) {
			treeViewer.setInput(provider);
			treeViewer.refresh();
		}
	}

	public String[] getOperandListSupport(List<Object> operands) {
		if (operands == null || operands.size() == 0) {
			return new String[] {};
		}
		String[] value = new String[operands.size()];
		for (int i = 0; i < operands.size(); i++) {
			if (operands.get(i) != null) {
				if (operands.get(i) instanceof MathOperand) {
					value[i] = ((MathOperand) operands.get(i)).getDisplayText();
				} else {
					value[i] = "";
				}
				//
			} else {
				value[i] = "";
			}
		}
		return value;
	}

	public abstract EditingSupport getOperand1EditingSupport(
			TreeViewer treeViewer);

	public abstract EditingSupport getOperand2EditingSupport(
			TreeViewer treeViewer);

	public Control createPartControl(Composite parent) {
		GridData gridData = new GridData();
		gridData.horizontalAlignment = SWT.FILL;
		gridData.grabExcessHorizontalSpace = true;
		gridData.verticalAlignment = SWT.FILL;
		gridData.grabExcessVerticalSpace = true;
		Composite composite = new Composite(parent, SWT.FILL | SWT.BORDER);
		composite.setLayoutData(gridData);
		GridLayout layout = new GridLayout();
		composite.setLayout(layout);
		layout.numColumns = 2;

		Composite treeContainer = new Composite(composite, SWT.BORDER);
		gridData = new GridData();
		treeContainer.setLayoutData(gridData);
		gridData.horizontalAlignment = SWT.FILL;
		gridData.grabExcessHorizontalSpace = true;
		gridData.verticalAlignment = SWT.FILL;
		gridData.grabExcessVerticalSpace = true;
		TreeColumnLayout treeLayout = new TreeColumnLayout();
		treeContainer.setLayout(treeLayout);
		treeViewer = new CheckboxTreeViewer(treeContainer, SWT.MULTI
				| SWT.FULL_SELECTION);
		Tree tree = treeViewer.getTree();
		tree.setHeaderVisible(true);
		treeViewer.setContentProvider(new LogicalListContentProvider());
		treeViewer.setCheckStateProvider(new ICheckStateProvider() {
			@Override
			public boolean isGrayed(Object element) {

				return false;
			}

			@Override
			public boolean isChecked(Object element) {

				return false;
			}
		});

		TreeColumn valueColumn;
		valueColumn = new TreeColumn(tree, SWT.NONE);
		valueColumn.setText("Condition");
		treeLayout.setColumnData(valueColumn, new ColumnWeightData(6));
		TreeViewerColumn column2 = new TreeViewerColumn(treeViewer, valueColumn);
		column2.setLabelProvider(new ColumnLabelProvider() {
			public String getText(Object element) {
				if (element != null && element instanceof Displayable) {
					return ((Displayable) element).getDisplayText();
				}
				return "";
			}

			public Image getImage(Object element) {

				return Constants.BOOLEAN_IMAGE;
			}
		});
		TreeColumn operand1Column;
		operand1Column = new TreeColumn(tree, SWT.NONE);
		operand1Column.setText("Operand1");
		treeLayout.setColumnData(operand1Column, new ColumnWeightData(2));
		TreeViewerColumn operand1ColumnViewer = new TreeViewerColumn(
				treeViewer, operand1Column);
		operand1ColumnViewer.setLabelProvider(new ColumnLabelProvider() {
			public String getText(Object element) {
				if (element != null && element instanceof CompareLogical) {
					MathOperand mathOperand = ((CompareLogical) element)
							.getOperand1();
					if (mathOperand != null) {
						return mathOperand.getDisplayText();
					}
				}
				return "";
			}

			public Image getImage(Object element) {
				return null;
			}
		});
		EditingSupport editingSupport1 = getOperand1EditingSupport(treeViewer);

		operand1ColumnViewer.setEditingSupport(editingSupport1);
		TreeColumn operatorColumn;
		operatorColumn = new TreeColumn(tree, SWT.NONE);
		operatorColumn.setText("Operator");
		treeLayout.setColumnData(operatorColumn, new ColumnWeightData(2));
		TreeViewerColumn operatorColumnViewer = new TreeViewerColumn(
				treeViewer, operatorColumn);
		operatorColumnViewer.setLabelProvider(new ColumnLabelProvider() {
			public String getText(Object element) {
				if (element instanceof CompareLogical) {
					CompareOperator compareOperator = ((CompareLogical) element)
							.getOperator();
					if (compareOperator != null) {
						return compareOperator.getDisplayText();
					}
				}
				return "";
			}

			public Image getImage(Object element) {
				return null;
			}
		});
		final TreeViewerColumn operand2ColumnViewer;
		final List<CompareOperator> compareOperators = getCompareOperators();
		final String[] supportedCompareOperator = new String[compareOperators
				.size()];
		for (int i = 0; i < compareOperators.size(); i++) {
			if (compareOperators.get(i) != null) {
				supportedCompareOperator[i] = compareOperators.get(i)
						.getDisplayText();
			} else {
				supportedCompareOperator[i] = "";
			}
		}

		operatorColumnViewer.setEditingSupport(new EditingSupport(treeViewer) {
			protected void setValue(Object arg0, Object arg1) {
				if (arg0 instanceof CompareLogical) {
					CompareLogical compareOperator = ((CompareLogical) arg0);
					compareOperator.setOperator(compareOperators
							.get((Integer) arg1));
					if (compareOperator.getOperator() != null
							&& !compareOperator.getOperator()
									.supportTwoOperand()) {
						compareOperator.setOperand2(null);

					}
					treeViewer.refresh();
					if (dirtyListener != null) {
						dirtyListener.resourceChanged(null);
					}
				}
			}

			protected Object getValue(Object arg0) {
				if (arg0 instanceof CompareLogical) {
					CompareOperator compareOperator = ((CompareLogical) arg0)
							.getOperator();
					if (compareOperator != null) {
						return compareOperators.indexOf(compareOperator);
					}
				}
				return 0;
			}

			ComboBoxCellEditor libEditor = new ComboBoxCellEditor(
					(Composite) treeViewer.getControl(),
					supportedCompareOperator);

			protected CellEditor getCellEditor(Object arg0) {

				return libEditor;
			}

			protected boolean canEdit(Object arg0) {
				if (arg0 instanceof CompareLogical)
					return true;
				return false;
			}
		});

		TreeColumn operand2Column;
		operand2Column = new TreeColumn(tree, SWT.NONE);
		operand2Column.setText("Operand2");
		treeLayout.setColumnData(operand2Column, new ColumnWeightData(2));
		operand2ColumnViewer = new TreeViewerColumn(treeViewer, operand2Column);
		operand2ColumnViewer.setLabelProvider(new ColumnLabelProvider() {
			public String getText(Object element) {
				if (element != null && element instanceof CompareLogical) {
					MathOperand mathOperand = ((CompareLogical) element)
							.getOperand2();
					if (mathOperand != null) {
						return mathOperand.getDisplayText();
					}
				}
				return "";
			}

			public Image getImage(Object element) {
				return null;
			}
		});

		EditingSupport editingSupport2 = getOperand2EditingSupport(treeViewer);

		operand2ColumnViewer.setEditingSupport(editingSupport2);
		// TODO: set lai
		// getSite().setSelectionProvider(treeViewer);

		treeViewer.setInput(provider);

		treeViewer.setAutoExpandLevel(TreeViewer.ALL_LEVELS);

		Composite wrapper = new Composite(composite, SWT.NONE);
		RowLayout rowLayout = new RowLayout();
		wrapper.setLayout(rowLayout);
		rowLayout.type = SWT.VERTICAL;

		final Button addButton = new Button(wrapper, SWT.NONE);
		addButton.setText("Add");

		addButton.addMouseListener(new MouseListener() {

			public void mouseUp(MouseEvent e) {

			}

			public void mouseDown(MouseEvent e) {
				Logical logical = new CompareLogical();
				List<Logical> logicals = provider.getLogicals();
				if (logicals == null) {
					logicals = new ArrayList<Logical>();
					provider.setLogicals(logicals);
				}
				logicals.add(logical);

				treeViewer.refresh();
				if (dirtyListener != null) {
					dirtyListener.resourceChanged(null);
				}
			}

			public void mouseDoubleClick(MouseEvent e) {

			}
		});

		final Button delButton = new Button(wrapper, SWT.NONE);
		delButton.setText("Delete");

		delButton.addMouseListener(new MouseListener() {

			public void mouseUp(MouseEvent e) {

			}

			public void mouseDown(MouseEvent e) {
				Object[] objects = treeViewer.getCheckedElements();

				List<Logical> logicals = provider.getLogicals();
				if (logicals == null) {
					logicals = new ArrayList<Logical>();
					provider.setLogicals(logicals);
				}
				if (objects != null) {
					for (int i = 0; i < objects.length; i++) {
						logicals.remove(objects[i]);
					}
					treeViewer.refresh();
					if (dirtyListener != null) {
						dirtyListener.resourceChanged(null);
					}
				}
			}

			public void mouseDoubleClick(MouseEvent e) {

			}
		});
		final Button andButton = new Button(wrapper, SWT.NONE);
		andButton.setText("AND");

		andButton.addMouseListener(new MouseListener() {

			public void mouseUp(MouseEvent e) {

			}

			public void mouseDown(MouseEvent e) {
				Object[] objects = treeViewer.getCheckedElements();
				List<Logical> logicals = provider.getLogicals();
				if (logicals == null) {
					logicals = new ArrayList<Logical>();
					provider.setLogicals(logicals);
				}
				if (objects != null && objects.length >= 2) {
					int index = -1;
					int find;
					for (int i = 0; i < objects.length; i++) {
						find = logicals.indexOf(objects[i]);
						if (find != -1) {
							if (index == -1 || index > find) {
								index = find;
							}
						}
					}
					if (index != -1) {
						ComplexLogical complexLogical = new ComplexLogical();
						complexLogical.setLogical1((Logical) objects[0]);
						complexLogical.setOperator(andOperator);
						complexLogical.setLogical2((Logical) objects[1]);
						for (int i = objects.length - 1; i >= 2; i--) {
							complexLogical = new ComplexLogical(complexLogical,
									(Logical) objects[i], andOperator);
						}
						logicals.set(index, complexLogical);
						for (int i = 0; i < objects.length; i++) {
							logicals.remove(objects[i]);
						}
					}
					treeViewer.refresh();
					if (dirtyListener != null) {
						dirtyListener.resourceChanged(null);
					}
				}
			}

			public void mouseDoubleClick(MouseEvent e) {

			}
		});
		final Button orButton = new Button(wrapper, SWT.NONE);
		orButton.setText("Or");

		orButton.addMouseListener(new MouseListener() {

			public void mouseUp(MouseEvent e) {

			}

			public void mouseDown(MouseEvent e) {
				Object[] objects = treeViewer.getCheckedElements();
				List<Logical> logicals = provider.getLogicals();
				if (logicals == null) {
					logicals = new ArrayList<Logical>();
					provider.setLogicals(logicals);
				}
				if (objects != null && objects.length >= 2) {
					int index = -1;
					int find;
					for (int i = 0; i < objects.length; i++) {
						find = logicals.indexOf(objects[i]);
						if (find != -1) {
							if (index == -1 || index > find) {
								index = find;
							}
						}
					}
					if (index != -1) {
						ComplexLogical complexLogical = new ComplexLogical();
						complexLogical.setLogical1((Logical) objects[0]);
						complexLogical.setOperator(orOperator);
						complexLogical.setLogical2((Logical) objects[1]);
						for (int i = objects.length - 1; i >= 2; i--) {
							complexLogical = new ComplexLogical(complexLogical,
									(Logical) objects[i], orOperator);
						}
						logicals.set(index, complexLogical);
						for (int i = 0; i < objects.length; i++) {
							logicals.remove(objects[i]);
						}
					}
					treeViewer.refresh();
					if (dirtyListener != null) {
						dirtyListener.resourceChanged(null);
					}
				}
			}

			public void mouseDoubleClick(MouseEvent e) {

			}
		});

		final Button notButton = new Button(wrapper, SWT.NONE);
		notButton.setText("Not");
		notButton.addMouseListener(new MouseListener() {
			public void mouseUp(MouseEvent e) {

			}

			public void mouseDown(MouseEvent e) {
				Object[] objects = treeViewer.getCheckedElements();
				List<Logical> logicals = provider.getLogicals();
				if (logicals == null) {
					logicals = new ArrayList<Logical>();
					provider.setLogicals(logicals);
				}
				if (objects != null && objects.length == 1) {
					int index = -1;
					int find;
					for (int i = 0; i < objects.length; i++) {
						find = logicals.indexOf(objects[i]);
						if (find != -1) {
							if (index == -1 || index > find) {
								index = find;
							}
						}
					}
					if (index != -1) {
						ComplexLogical complexLogical = new ComplexLogical();
						complexLogical.setLogical1((Logical) objects[0]);
						complexLogical.setOperator(notOperator);
						logicals.set(index, complexLogical);
						treeViewer.refresh();
						if (dirtyListener != null) {
							dirtyListener.resourceChanged(null);
						}
					}
				}
			}

			public void mouseDoubleClick(MouseEvent e) {

			}
		});

		final Button unButton = new Button(wrapper, SWT.NONE);
		unButton.setText("Un-group");
		unButton.addMouseListener(new MouseListener() {
			public void mouseUp(MouseEvent e) {

			}

			public void mouseDown(MouseEvent e) {
				Object[] objects = treeViewer.getCheckedElements();
				List<Logical> logicals = provider.getLogicals();
				if (logicals == null) {
					logicals = new ArrayList<Logical>();
					provider.setLogicals(logicals);
				}
				if (objects != null && objects.length == 1
						&& objects[0] != null
						&& objects[0] instanceof ComplexLogical) {
					int index = -1;
					int find;
					for (int i = 0; i < objects.length; i++) {
						find = logicals.indexOf(objects[i]);
						if (find != -1) {
							if (index == -1 || index > find) {
								index = find;
							}
						}
					}
					if (index != -1) {

						ComplexLogical complexLogical = (ComplexLogical) objects[0];
						if (complexLogical.getOperator().supportTwoOperand()) {
							if (index == logicals.size() - 1) {
								logicals.set(index,
										complexLogical.getLogical1());
								logicals.add(complexLogical.getLogical2());
							} else {
								logicals.set(index,
										complexLogical.getLogical1());
								logicals.add(index + 1,
										complexLogical.getLogical2());
							}
						} else {
							logicals.set(index, complexLogical.getLogical1());
						}
						treeViewer.refresh();
						if (dirtyListener != null) {
							dirtyListener.resourceChanged(null);
						}
					}
				}
			}

			public void mouseDoubleClick(MouseEvent e) {

			}
		});

		final Button button = new Button(wrapper, SWT.NONE);
		button.setText("Select All");

		button.addMouseListener(new MouseListener() {

			public void mouseUp(MouseEvent e) {

			}

			@SuppressWarnings("deprecation")
			public void mouseDown(MouseEvent e) {
				treeViewer.setAllChecked(true);
			}

			public void mouseDoubleClick(MouseEvent e) {

			}
		});
		final Button button2 = new Button(wrapper, SWT.NONE);
		button2.setText("Deselect All");

		button2.addMouseListener(new MouseListener() {

			public void mouseUp(MouseEvent e) {

			}

			@SuppressWarnings("deprecation")
			public void mouseDown(MouseEvent e) {
				treeViewer.setAllChecked(false);
			}

			public void mouseDoubleClick(MouseEvent e) {

			}
		});
		return composite;
	}

}
